package com.yequan.encrypt;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


public class AESEncrypt {

    /*
     * 加密秘钥（长度必须是16位）
     * 1byte = 8bit
     * 16byte = 128bit（128位）
     */
    private final String SECRET_KEY = "P*&S!@D#$B^&A?ES";
    private final String SECRET_IVP_KEY = "P*&S!@D#$B^&A?ES";

    private AESEncrypt() {
    }

    public static AESEncrypt getInstance() {
        return new AESEncrypt();
    }

    /**
     * AES加密的私有实现方法
     *
     * @param sSrc
     * @param sKey
     * @param sIv
     * @return
     */
    private byte[] encrypt(byte[] sSrc, String sKey, String sIv) throws Exception {
        byte[] encrypt;
        if (sKey == null) {
            System.out.println("Key为空null。");
        }
        // 判断Key是否为16位
        if (sKey.length() != 16) {
            System.out.println("Key长度不是16位");
        }
        byte[] raw = sKey.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");// "算法/模式/补码方式"
        IvParameterSpec iv = new IvParameterSpec(sIv.getBytes());// 使用CBC模式，需要一个向量iv，可增加加密算法的强度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(sSrc);
        encrypt = Base64.encode(encrypted);// 此处使用BAES64做转码功能，同时能起到2次加密的作用。
        return encrypt;
    }

    /**
     * 平台使用的AES加密方法
     *
     * @param rawPass rawPass 要进行DES加密的字符串
     * @param salt    salt 密码算子对象
     * @return String encPass AES加密后的字符串
     */
    public byte[] encodePassword(byte[] rawPass, Object salt) throws Exception {
        byte[] enPass;
        String sKey = salt.toString().substring(0, 16);
        String sIv = sKey;
        enPass = encrypt(rawPass, sKey, sIv);
        return enPass;
    }

    /**
     * PSDB使用的AES加密方法
     *
     * @param rawPass 要进行DES加密的字符串
     * @return
     */
    public byte[] encodePassword(byte[] rawPass) {
        byte[] enPass;
        try {
            enPass = encrypt(rawPass, this.SECRET_KEY, this.SECRET_IVP_KEY);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DataSecurityException("私密数据AES解密异常!");
        }
        return enPass;
    }


    /**
     * AES解密的私有实现方法
     *
     * @param sSrc
     * @param sKey
     * @param sIv
     * @return
     */
    private byte[] deCrypt(byte[] sSrc, String sKey, String sIv) {
        byte[] rawPass = new byte[0];
        Cipher cipher = null;
        try {
            // 判断Key是否正确
            if (sKey == null) {
                System.out.println("Key为空null。");
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                System.out.println("Key长度不是128位");
            }
            byte[] raw = sKey.getBytes("ASCII");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec ivp = new IvParameterSpec(sIv.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivp);
            byte[] encrypted1 = Base64.decode(sSrc);// 先用bAES64解密
            byte[] original = cipher.doFinal(encrypted1);
            rawPass = original;
        } catch (Exception ex) {
            System.out.println("AES解密的私有实现方法出错。");
        }
        return rawPass;
    }

    /**
     * 平台使用的AES解密方法
     *
     * @param encPass 要进行DES加密的字符串
     * @param salt    密码算子对象
     * @return String encPass AES解密后的字符串
     */
    public byte[] decodePassword(byte[] encPass, Object salt) {
        byte[] rawPass;
        String sKey = salt.toString().substring(0, 16);
        String sIv = sKey;
        rawPass = deCrypt(encPass, sKey, sIv);
        return rawPass;
    }

    /**
     * PSDB使用的AES解密方法
     *
     * @param encPass 要进行DES加密的字符串
     * @return AES加密后的字符串
     */
    public byte[] decodePassword(byte[] encPass) {
        byte[] rawPass;
        rawPass = deCrypt(encPass, this.SECRET_KEY, this.SECRET_IVP_KEY);
        return rawPass;
    }
    public static void main(String[] args) {
        byte[] jiami = new byte[0];

        try {
            jiami = AESEncrypt.getInstance().encodePassword("psdb_v9".getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("加密后的密码数据为：" + new String(jiami));
        System.out.println("验证加密数据的解密，结果是否为你加密的明文：" + new String(AESEncrypt.getInstance().decodePassword(jiami)));

    }

}
